#ifndef SNCNEIGHBOR_HH
#define SNCNEIGHBOR_HH 1

//#include "sncpacket.hh"
//
//#include "snc.hh"

//#include "list.hh"
#include "packetpool.hh"
#include "sncpacket.hh"


#include <click/packet.hh>
#include <click/hashtable.hh>
#include <click/vector.hh>
#include <click/string.hh>
#include <click/dequeue.hh>
#include <click/etheraddress.hh>



CLICK_DECLS

//class SNCNeighborManag;

class SNCNeighbor{
public:
	typedef SNCoding::List<Packet_v > Packet_list_v;
	SNCNeighbor(const uint8_t* mac,unsigned poolcap,Packet_list* send_pktq=0,uint8_t threhold=100,uint16_t pkt_seqno=0):
		_local_pkt_seq(pkt_seqno),
		_threhold(threhold),_link_credit_table(0.0),
		_pktpool(poolcap),
		_send_pktq(send_pktq){
		memcpy(_mac,mac,6);
		DPrintf("SNCNeighbor constructed!");
	}
	~SNCNeighbor(){}
	bool operator==(const uint8_t* mac){
		return 0==memcmp(_mac,mac,6);
	}
	//uint32_t get_id(){return _ip;}

	uint16_t get_seq(){
		return _local_pkt_seq++;
	}
	void update_link_credit(uint32_t id,float credit){
		_link_credit_table.set(id,credit);
	}
	void update_pool(uint32_t pkt_id){
		//be careful , pkt_id alreadt have?
		_pktpool.store(pkt_id);
	}
	float get_pkt_credit(uint32_t pkt_id){
		if(_pktpool.find(pkt_id))
			return 1.0;
		else return _link_credit_table.get(pkt_id);
	}
	bool add_pkt(Packet* p){
		Packet_list::iterator iter=_send_pktq->push_back(p);
		if(iter==_send_pktq->end()) return false; //list is full
		if(p->length()>=_threhold)
			_long_pktq.push_back(iter);
		else _short_pktq.push_back(iter);
		return true;
	}
	void remove_pkt(Packet_v* p){
		if(_waitting_ack_pktq.erase(*p)) {
			(**p)->kill();
			_send_pktq->erase(*p);
			return;
		}
		Packet_list_v* pktq_v;
		if((**p)->length()>=_threhold) pktq_v=&_long_pktq;
		else pktq_v=&_short_pktq;
		(**p)->kill();
		pktq_v->erase(*p);
		_send_pktq->erase(*p);
	}
	void received_ack(uint16_t last_ack,bitmap_sizetype bitmap);
	bool encode_check(Natives& natives);
	Packet* get_encode_pkt(const Packet* p);
	void set_poolcap(unsigned cap){
		_pktpool.set_cap(cap);
	}
	void set_threshold(unsigned threshold){
		_threhold=threshold;
	}
	//void set_sendq(Packet_list* sendpktq){_send_pktq=sendpktq;}

protected:
	uint16_t 	_local_pkt_seq;
	//uint32_t 	_ip;
	uint8_t		_mac[6];
	uint8_t		_threhold;
	float		_probability;
	//DEQueue<sendq > _waitedack;
	HashTable<uint32_t,float > _link_credit_table;
	NeighborPacketPool _pktpool; //only store report info
	Packet_list_v _long_pktq;
	Packet_list_v _short_pktq;
	Packet_list_v _waitting_ack_pktq;
	Packet_list* _send_pktq;
	//uint8_t		_echo_num;

	friend class SNCNeighborManag;
};

class SNC;

class SNCNeighborManag{
public:
	SNCNeighborManag(SNC* s){
		_snc=s;
		DPrintf("SNCNeighborManag constructed!");
		//_send_pktq=&(_snc->_sendq);
	}
	~SNCNeighborManag(){
		Vector<SNCNeighbor* >::iterator iter;
		for(iter=_neighbors.begin();iter!=_neighbors.end();iter++){
			delete *iter;
		}
	}
	void codepoll(Natives& natives);
	void update_link_credit(uint32_t id){}
	void update_pktpool(const uint8_t* mac,report_header* data,uint32_t size);
	void update_pktpool(const uint8_t* mac,encoded_header* data,uint32_t size);
	void update_pktpool(const uint8_t* mac,uint32_t pkt_id);
	void update_ackqueue(const uint8_t* src,ack_header* ack_data,uint32_t size);
	bool add_to_sendq(const uint8_t* dst,Packet* p);
	void remove_from_sendq(const uint8_t* dst,Packet_v p_v );
	uint16_t get_pkt_seqno(const uint8_t* mac);
	void set_poolcap(unsigned cap);
	void set_threshold(unsigned threshold);

protected:
	SNCNeighbor* create_neighbor(const uint8_t* mac,uint16_t pkt_seqno=0);

protected:
	Vector<SNCNeighbor* > _neighbors;
	//Packet_list* _send_pktq;
	//EtherAddress _eth;
	SNC* _snc;

};
CLICK_ENDDECLS



#endif
